#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <windows.h>
#include <locale.h>

// 根据操作系统选择正确的头文件
#ifdef _WIN32
#include <direct.h> // Windows 系统
#else
#include <unistd.h> // Unix/Linux/macOS 系统
#endif

#define BUFFER_SIZE 1024
#define FILL_BYTE 0xFF

#define MERGE_POSITION 0x1400UL // app.bin文件开始写入位置
#define CHANG_DATA_POSITION 0x1300UL // 需要修改数据的位置
#define ALL_POSITION 0x8000UL // 总的flash容量，因为目前是32k的芯片，所以最后地址为0x8000

const char* app_file_path =
	"../projects/TCM33x/Keil/customer/stepper_leili_spwm/tcm33x_stepper_boot.bin";
const char* bootloader_file_path =
	"../outputs/tcm33x_bootloader_highspeedV1.0.bin";
const char* output_file_path = "../outputs/after_merge.bin";

const uint8_t new_data[25] = {
	0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x58, 0x00, 0x00, 0x5C, 0x34, 0xCF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0x01, 0x00, 0x00, 0x00, 0x00
};

int main()
{
	FILE* bootFile = NULL;
	FILE* appFile = NULL;
	FILE* outputFile = NULL;

	char exePath[1024] = {0}; // 缓冲区用于存储可执行文件路径
	char buffer[BUFFER_SIZE];
	char cwd[1024]; // 缓冲区用于存储路径
	size_t bytesRead;

#ifdef _WIN32
	// 获取可执行文件路径（Windows）
	GetModuleFileName(NULL, exePath, sizeof(exePath));
#else
	// 获取可执行文件路径（Linux/Unix）
	ssize_t len = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
	if (len != -1) {
		exePath[len] = '\0';
	}
#endif

	printf("Executable File Path: %s\n", exePath);

	// 获取当前工作目录
	if (getcwd(cwd, sizeof(cwd)) != NULL)
	{
		printf("Current Working Directory: %s\n", cwd);
	}
	else
	{
		perror("getcwd() error!");

		return -1;
	}

	// 提取可执行文件所在目录
	char* lastSlash = strrchr(exePath, '\\'); // Windows 使用反斜杠
	if (!lastSlash)
	{
		lastSlash = strrchr(exePath, '/'); // Linux/Unix 使用正斜杠
	}

	if (lastSlash)
	{
		*lastSlash = '\0'; // 截断路径，保留目录部分
	}
	printf("lastSlash File Path: %s\n", exePath);

	// 切换工作目录到可执行文件所在目录
	if (chdir(exePath) != 0)
	{
		perror("chdir() error!");

		return -1;
	}

	// 打开 bootloader.bin 和 app.bin 文件
	bootFile = fopen(bootloader_file_path, "rb");
	if (bootFile == NULL)
	{
		perror("无法打开 bootlaoder.bin");

		return EXIT_FAILURE;
	}

	appFile = fopen(app_file_path, "rb");
	if (appFile == NULL)
	{
		perror("无法打开 app.bin");
		fclose(bootFile);

		return EXIT_FAILURE;
	}

	// 创建 c.bin 文件
	outputFile = fopen(output_file_path, "wb");
	if (outputFile == NULL)
	{
		perror("无法创建 output.bin");
		fclose(bootFile);
		fclose(appFile);

		return EXIT_FAILURE;
	}

	// 将 bootloader.bin 的内容写入 c.bin
	while ((bytesRead = fread(buffer, 1, BUFFER_SIZE, bootFile)) > 0)
	{
		fwrite(buffer, 1, bytesRead, outputFile);
	}

	// 获取 bootloader.bin 的大小
	long fileSizeA = ftell(bootFile);
	rewind(bootFile);

	// 如果 bootloader.bin 的大小小于 0x1400，则填充 0xFF
	if (fileSizeA < MERGE_POSITION)
	{
		for (long i = fileSizeA; i < MERGE_POSITION; i++)
		{
			fputc(FILL_BYTE, outputFile);
		}
	}
	else
	{
		// 移动文件指针到 0x1400 位置
		fseek(outputFile, MERGE_POSITION, SEEK_SET);
	}

	fseek(outputFile, MERGE_POSITION, SEEK_SET);

	while ((bytesRead = fread(buffer, 1, BUFFER_SIZE, appFile)) > 0)
	{
		fwrite(buffer, 1, bytesRead, outputFile);
	}

	// 获取 app.bin 的大小
	long fileSizeB = ftell(appFile);
	rewind(appFile);

	// 如果 app.bin 的内容没有填满 0x1400 之后的位置，则继续填充 0xFF
	if (fileSizeB < (ALL_POSITION - MERGE_POSITION))
	{
		for (long i = fileSizeB; i < (ALL_POSITION - MERGE_POSITION); i++)
		{
			fputc(FILL_BYTE, outputFile);
		}
	}

	// 关闭所有文件
	fclose(bootFile);
	fclose(appFile);
	fclose(outputFile);

	// 打开文件
	outputFile = fopen(output_file_path, "r+b"); // 以读写模式打开
	if (outputFile == NULL)
	{
		perror("无法打开文件");

		return EXIT_FAILURE;
	}

	// 使用 fseek 移动文件指针到指定位置
	if (fseek(outputFile, CHANG_DATA_POSITION, SEEK_SET) != 0)
	{
		perror("无法定位到指定位置");
		fclose(outputFile);

		return EXIT_FAILURE;
	}

	// 写入新数据
	if (fwrite(new_data, 1, sizeof(new_data), outputFile) != sizeof(new_data))
	{
		perror("写入文件时出错");
		fclose(outputFile);

		return EXIT_FAILURE;
	}

	// 关闭文件
	fclose(outputFile);

	printf("文件已成功合并为 merged_output.bin\n");

	return EXIT_SUCCESS;
}